import React, {
  useRef,
  ReactElement,
  isValidElement,
} from 'react'
import {
  useSpring,
  animated,
} from '@react-spring/web'
import classNames from 'classnames'
import { RiArrowDownSLine } from '@remixicon/react'
import { useMount } from '@/library/hooks/use-mount'
import { usePropsValue } from '../../hooks/use-props-value'
import { useIsomorphicUpdateLayoutEffect } from '../../hooks/use-isomorphic-update-layout-effect'
import { traverseReactNode } from '../../utils/traverse-react-node'
import { withNativeProps } from '../../utils/native-props'
import { useShouldRender } from '../../utils/should-render'
import List from '../List'
import type {
  CollapseProps,
  CollapsePanelProps,
  CollapsePanelContentProps,
} from './type'

const classPrefix = 'rt-collapse'

export const CollapsePanel: React.FC<CollapsePanelProps> = () => null

const CollapsePanelContent: React.FC<CollapsePanelContentProps> = (props) => {
  const {
    destroyOnClose,
    forceRender,
    immediate,
    visible,
    children,
  } = props

  const innerRef = useRef<HTMLDivElement>(null)

  const shouldRender = useShouldRender(
    visible,
    destroyOnClose,
    forceRender,
  )

  const [{ height }, api] = useSpring(() => ({
    from: { height: 0 },
    config: {
      precision: 0.01,
      mass: 1,
      tension: 200,
      friction: 25,
      clamp: true,
    },
  }))

  useMount(() => {
    if (!visible) return
    const inner = innerRef.current
    if (!inner) return
    api.start({
      height: inner.offsetHeight,
      immediate: !immediate,
    })
  })

  useIsomorphicUpdateLayoutEffect(() => {
    const inner = innerRef.current
    if (!inner) return
    if (visible) {
      api.start({
        height: inner.offsetHeight,
      })
    } else {
      api.start({
        height: 0,
      })
    }
  }, [visible])

  return (
    <animated.div
      className={classNames(`${classPrefix}-panel-content`, {
        [`${classPrefix}-panel-content-active`]: visible,
      })}
      style={{
        height: height.to((v) => {
          /** `idle`
           * Equals true when not advancing on each frame
           */
          if (height.idle && visible) {
            return 'auto'
          }
          return v
        }),
      }}
    >
      <div
        className={`${classPrefix}-panel-content-inner`}
        ref={innerRef}
      >
        <List.Item
          style={{
            wordBreak: 'break-all',
            wordWrap: 'break-word',
          }}
        >
          {shouldRender && children}
        </List.Item>
      </div>
    </animated.div>
  )
}

export const Collapse: React.FC<CollapseProps> = (props) => {
  const {
    arrow,
    accordion,
    activeKey,
    children,
    defaultActiveKey,
    onChange,
  } = props

  const panels: ReactElement<CollapsePanelProps>[] = []

  traverseReactNode(children, (child) => {
    if (!isValidElement<CollapsePanelProps>(child)) return
    const { key } = child
    if (typeof key !== 'string') return

    panels.push(child)
  })

  const handlePropsValue = () => {
    if (!accordion) {
      return {
        value: activeKey,
        defaultValue: defaultActiveKey ?? [],
        onChange,
      }
    }

    const initValue: {
      value?: string[]
      defaultValue: string[]
      onChange: (v: string[]) => void
    } = {
      value: [],
      defaultValue: [],
      onChange: (v) => {
        onChange?.(v[0] ?? null)
      },
    }

    if (activeKey === undefined) {
      initValue.value = undefined
    } else if (activeKey !== null) {
      initValue.value = [activeKey]
    }

    if (![null, undefined].includes(defaultActiveKey as null | undefined)) {
      initValue.defaultValue = [defaultActiveKey as string]
    }

    return initValue
  }

  const [actActiveKey, setActActiveKey] = usePropsValue(handlePropsValue())

  // actActiveKey 不可能为null 且 actActiveKey 必然是数组 - 所有这个判断没什么意义
  // const actActiveKeyList = actActiveKey === null ? [] : Array.isArray(actActiveKey) ? actActiveKey : [actActiveKey]

  const actActiveKeyList = actActiveKey

  return withNativeProps(
    props,
    <div
      className={classPrefix}
    >
      <List>
        {
          panels.map((panel) => {
            const key = panel.key as string
            const active = actActiveKeyList.includes(key)
            const handleClick = (event: React.MouseEvent<Element, MouseEvent>) => {
              if (accordion) {
                if (active) {
                  setActActiveKey([])
                } else {
                  setActActiveKey([key])
                }
              } else if (active) {
                setActActiveKey(actActiveKeyList.filter((v) => v !== key))
              } else {
                setActActiveKey([...actActiveKeyList, key])
              }
              panel.props.onClick?.(event)
            }
            const renderArrow = () => {
              let actArrow: CollapseProps['arrow'] = <RiArrowDownSLine style={{ color: 'var(--rt-color-primary)' }} />
              if (arrow !== undefined) {
                actArrow = arrow
              }
              if (panel.props.arrow !== undefined) {
                actArrow = panel.props.arrow
              }

              return typeof actArrow === 'function' ? (
                actArrow(active)
              ) : (
                <div
                  className={classNames(`${classPrefix}-arrow`, {
                    [`${classPrefix}-arrow-active`]: active,
                  })}
                >
                  {actArrow}
                </div>
              )
            }

            return (
              <React.Fragment key={key}>
                {
                  withNativeProps(
                    panel.props,
                    <List.Item
                      onClick={handleClick}
                      className={`${classPrefix}-panel-header`}
                      disabled={panel.props.disabled}
                      arrow={renderArrow()}
                    >
                      {panel.props.title}
                    </List.Item>,
                  )
                }
                <CollapsePanelContent
                  visible={active}
                  destroyOnClose={!!panel.props.destroyOnClose}
                  forceRender={!!panel.props.forceRender}
                  immediate={!!panel.props.immediate}
                >
                  {panel.props.children}
                </CollapsePanelContent>
              </React.Fragment>
            )
          })
        }
      </List>
    </div>,
  )
}
